/* * Copyright 2012 Michael Chang, Tai-Lin Chu, Artin Menachekanian, * Charles Rudolph, Eduard Sedakov, Suzanna Whiteside * * This file is part of ServerLibraryManager. * * ServerLibraryManager is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ServerLibraryManager is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with ServerLibraryManager. If not, see <http://www.gnu.org/licenses/>. */ package edu.ucla.loni.client; import edu.ucla.loni.shared.*; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.http.client.URL; import com.google.gwt.regexp.shared.MatchResult; import com.google.gwt.regexp.shared.RegExp; import com.google.gwt.regexp.shared.SplitResult; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.FileUpload; import com.google.gwt.user.client.ui.FormPanel; import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent; import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.Hidden; import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.TextBox; import com.smartgwt.client.data.Record; import com.smartgwt.client.types.Alignment; import com.smartgwt.client.types.AnimationEffect; import com.smartgwt.client.types.KeyNames; import com.smartgwt.client.types.ListGridComponent; import com.smartgwt.client.types.SelectionAppearance; import com.smartgwt.client.types.VerticalAlignment; import com.smartgwt.client.util.BooleanCallback; import com.smartgwt.client.util.SC; import com.smartgwt.client.util.ValueCallback; import com.smartgwt.client.widgets.events.ClickEvent; import com.smartgwt.client.widgets.events.ClickHandler; import com.smartgwt.client.widgets.events.ResizedEvent; import com.smartgwt.client.widgets.events.ResizedHandler; import com.smartgwt.client.widgets.Button; import com.smartgwt.client.widgets.Dialog; import com.smartgwt.client.widgets.Label; import com.smartgwt.client.widgets.form.DynamicForm; import com.smartgwt.client.widgets.form.fields.ComboBoxItem; import com.smartgwt.client.widgets.form.fields.FormItem; import com.smartgwt.client.widgets.form.fields.SelectItem; import com.smartgwt.client.widgets.form.fields.StaticTextItem; import com.smartgwt.client.widgets.form.fields.TextAreaItem; import com.smartgwt.client.widgets.form.fields.TextItem; import com.smartgwt.client.widgets.form.fields.events.ChangedEvent; import com.smartgwt.client.widgets.form.fields.events.ChangedHandler; import com.smartgwt.client.widgets.form.fields.events.KeyUpEvent; import com.smartgwt.client.widgets.form.fields.events.KeyUpHandler; import com.smartgwt.client.widgets.grid.ListGrid; import com.smartgwt.client.widgets.grid.ListGridField; import com.smartgwt.client.widgets.grid.ListGridRecord; import com.smartgwt.client.widgets.grid.events.RecordClickEvent; import com.smartgwt.client.widgets.grid.events.RecordClickHandler; import com.smartgwt.client.widgets.grid.events.RecordDoubleClickEvent; import com.smartgwt.client.widgets.grid.events.RecordDoubleClickHandler; import com.smartgwt.client.widgets.grid.events.SelectionUpdatedEvent; import com.smartgwt.client.widgets.grid.events.SelectionUpdatedHandler; import com.smartgwt.client.widgets.layout.HLayout; import com.smartgwt.client.widgets.layout.VLayout; import com.smartgwt.client.widgets.menu.Menu; import com.smartgwt.client.widgets.menu.MenuItem; import com.smartgwt.client.widgets.menu.MenuItemSeparator; import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent; import com.smartgwt.client.widgets.toolbar.ToolStrip; import com.smartgwt.client.widgets.toolbar.ToolStripButton; import com.smartgwt.client.widgets.tree.Tree; import com.smartgwt.client.widgets.tree.TreeGrid; import com.smartgwt.client.widgets.tree.TreeNode; import com.smartgwt.client.widgets.tree.events.NodeContextClickEvent; import com.smartgwt.client.widgets.tree.events.NodeContextClickHandler; /** * Entry point classes define <code>onModuleLoad()</code>. */ public class ServerLibraryManager implements EntryPoint { //////////////////////////////////////////////////////////// // Private Variables //////////////////////////////////////////////////////////// /** * Remote Server Proxy to talk to the server-side code */ private FileServiceAsync fileServer = GWT.create(FileService.class); /** * Default Root Directory */ private String rootDirectoryDefault = "/usr/share/tomcat6/CraniumLibrary"; /** * Current Root Directory */ private Directory rootDirectory = null; /** * Label displaying the current root directory */ private Label rootDirectoryDisplay = new Label(rootDirectoryDefault); /** * Label displaying the number of selected files * <p> * Set in: onModuleLoad * <br> * Updated in: updateSelected; */ private Label numSelectedLabel = new Label("0 File(s) Selected"); /** * Workarea * <p> * Updated by a lot of functions */ private final VLayout workarea = new VLayout(); /** * Last pipefile that was viewed */ private int lastPipefileId = -1; /** * Button that allows you to jump back to the last pipefile you viewed */ private final ToolStripButton backToLastPipefile = new ToolStripButton(); /** * Message * <p> * Updated with the last message */ private final Label message = new Label(); /** * Package Tree * <p> * Set in: treeRefresh * <br> * Used in: onModuleLoad */ private final Tree fullTree = new Tree(); /** * Results Tree * <p> * Set in: treeResults * <br> * Used in: onModuleLoad */ private final Tree resultsTree = new Tree(); /** * Tree Grid * <p> * Set in: onModuleLoad * <br> * Used in: selectionClickHandler, contextClickHandler, updateFullTree, updateResultsTree */ private final TreeGrid treeGrid = new TreeGrid(); /** * True if packages is the highest level folder in fullTree, * False if module type is the highest level folder in fullTree * <p> * Set in: onModuleLoad * <br> * Used in: selectionClickHandler, contextClickHandler, updateFullTree, updateResultsTree */ private boolean viewByPackage = true; /** * Int fileId => Pipefile pipe * <p> * Set in: treeRefresh * <br> * Used in: viewFile, editFile */ private final LinkedHashMap<Integer, Pipefile> pipes = new LinkedHashMap<Integer, Pipefile>(); /** * String key => TreeNode node, * each tree node is given a key which is either the path from the root to that node (used for folders) * <p> * Set in: treeRefresh * <br> * Used in: viewFile, editFile */ private final LinkedHashMap<String, TreeNode> nodes = new LinkedHashMap<String, TreeNode>(); /** * String groupName => Group g * <p> * Set in viewGroups * <br> * Used in editGroup */ private final LinkedHashMap<String, Group> groups = new LinkedHashMap<String, Group>(); /** * Pipefiles that are currently selected * <p> * Set in: selectionClickHandler * <br> * Used in: fileOperations */ private Pipefile[] selected = null; /** * Pipefiles that have been selected to be copied * <p> * Set in: contextClickHandler * <br> * Used in: contextClickHandler (a later event) */ private Pipefile[] toCopy = null; /** * Pipefiles that have been selected to be moved * <p> * Set in: contextClickHandler * <br> * Used in: contextClickHandler (a later event) */ private Pipefile[] toMove = null; /** * Set in: treeRefresh * <br> * Used in: fileOperations */ private String[] packages = null; /** * Returns all pipefiles related with the given record, * Gets the pipefiles from the */ private ArrayList<Pipefile> getPipefiles(ListGridRecord[] records, Tree t){ ArrayList<Pipefile> ret = new ArrayList<Pipefile>(); for (ListGridRecord r : records){ int fileId = r.getAttributeAsInt("fileId"); if (fileId != -1){ Pipefile p = pipes.get(fileId); ret.add(p); } else { String key = r.getAttribute("key"); TreeNode node = nodes.get(key); TreeNode[] children = t.getChildren(node); ret.addAll(getPipefiles(children, t)); } } return ret; } private void updateSelected(){ ListGridRecord[] selectedRecords = treeGrid.getSelectedRecords(); Tree tree = treeGrid.getTree(); ArrayList<Pipefile> selectedList = getPipefiles(selectedRecords, tree); selected = new Pipefile[selectedList.size()]; selected = selectedList.toArray(selected); int numSelected = selected.length; numSelectedLabel.setContents(numSelected + " File(s) Selected"); if (numSelected == 0){ basicInstructions(); } else if (numSelected == 1){ viewFile(selected[0]); } else { fileOperations(selected); } } /** * Handler for when the selection in the treeGrid is updated */ private SelectionUpdatedHandler selectedPipefilesHandler = new SelectionUpdatedHandler() { public void onSelectionUpdated(SelectionUpdatedEvent event){ updateSelected(); } }; private NodeContextClickHandler contextClickHandler = new NodeContextClickHandler() { public void onNodeContextClick(NodeContextClickEvent event){ TreeGrid grid = event.getViewer(); final Tree tree = grid.getData(); final TreeNode clicked = event.getNode(); updateSelected(); Menu contextMenu = new Menu(); if (tree.isFolder(clicked)){ if (clicked.getAttributeAsBoolean("moveHere") == true){ MenuItem paste = new MenuItem("Paste"); paste.setEnabled(toCopy != null || toMove != null); contextMenu.addItem(paste); paste.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler(){ public void onClick(MenuItemClickEvent event){ boolean copy = (toCopy != null); Pipefile[] toPaste = copy ? toCopy : toMove; if (copy){ copyFiles(toPaste, clicked.getName()); } else { moveFiles(toPaste, clicked.getName()); } } }); contextMenu.addItem(new MenuItemSeparator()); } } MenuItem copy = new MenuItem("Copy"); copy.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler(){ public void onClick(MenuItemClickEvent event){ toCopy = selected; toMove = null; } }); contextMenu.addItem(copy); MenuItem move = new MenuItem("Move"); move.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler(){ public void onClick(MenuItemClickEvent event){ toCopy = null; toMove = selected; } }); contextMenu.addItem(move); MenuItem download = new MenuItem("Download"); download.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler(){ public void onClick(MenuItemClickEvent event){ downloadFiles(selected); } }); contextMenu.addItem(download); MenuItem remove = new MenuItem("Remove"); remove.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler(){ public void onClick(MenuItemClickEvent event){ removeFiles(selected); } }); contextMenu.addItem(remove); grid.setContextMenu(contextMenu); } }; //////////////////////////////////////////////////////////// // On Module Load //////////////////////////////////////////////////////////// /** * Entry point method (basically main function) */ public void onModuleLoad() { // Header -- Title Label title = new Label (); title.setWidth100(); title.setAlign(Alignment.CENTER); title.setHeight(50); title.setContents("Loni Pipeline Server Library Manager"); title.setStyleName("title"); // Header -- ToolStrip ToolStripButton home = new ToolStripButton("Home"); home.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { basicInstructions(); } }); ToolStripButton importButton = new ToolStripButton("Import"); importButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { importForm(); } }); ToolStripButton groupsButton = new ToolStripButton("Manage Groups"); groupsButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { viewGroups(); } }); backToLastPipefile.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { Pipefile p = pipes.get(lastPipefileId); if (p != null){ viewFile(p); } else { backToLastPipefile.hide(); } } }); message.setStyleName("success"); message.setWidth100(); // Header -- Button Row ToolStrip mainToolStrip = new ToolStrip(); mainToolStrip.addSpacer(1); mainToolStrip.addButton(home); mainToolStrip.addSeparator(); mainToolStrip.addButton(importButton); mainToolStrip.addSeparator(); mainToolStrip.addButton(groupsButton); mainToolStrip.addSeparator(); mainToolStrip.addButton(backToLastPipefile); mainToolStrip.addFill(); mainToolStrip.addMember(message); backToLastPipefile.hide(); // Header VLayout header = new VLayout(); header.setHeight(75); header.addMember(title); header.addMember(mainToolStrip); // Workarea workarea.setWidth100(); workarea.setHeight100(); workarea.setPadding(10); basicInstructions(); // Left -- Root Directory -- Label rootDirectoryDisplay.setHeight(40); rootDirectoryDisplay.setAlign(Alignment.CENTER); rootDirectoryDisplay.setValign(VerticalAlignment.TOP); rootDirectoryDisplay.setStyleName("largerFont"); // Left -- Root Directory -- Form final TextItem rootNew = new TextItem(); rootNew.setShowTitle(false); rootNew.setWidth(280); final DynamicForm rootForm = new DynamicForm(); rootForm.setHeight(40); rootForm.setAlign(Alignment.CENTER); rootForm.setFields(rootNew); // Left -- Search Form final TextItem query = new TextItem(); query.setHint("Search"); query.setShowTitle(false); query.setShowHintInField(true); query.setWidth(280); query.addChangedHandler(new ChangedHandler(){ public void onChanged(ChangedEvent event){ String q = query.getValueAsString(); if (q != null && q.length() >= 2){ treeGrid.setData(resultsTree); updateResultsTree(q); } else { treeGrid.setData(fullTree); } } }); DynamicForm searchForm = new DynamicForm(); searchForm.setFields(new FormItem[] {query}); searchForm.setWidth100(); // Left -- Tool Strip final ToolStripButton byPackage = new ToolStripButton("View By Package"); byPackage.setDisabled(true); final ToolStripButton byType = new ToolStripButton("View By Module Type"); byType.setDisabled(false); byPackage.addClickHandler(new ClickHandler() { public void onClick (ClickEvent event){ byPackage.setDisabled(true); byType.setDisabled(false); viewByPackage = true; sortFullTree(); } }); byType.addClickHandler(new ClickHandler() { public void onClick (ClickEvent event){ byPackage.setDisabled(false); byType.setDisabled(true); viewByPackage = false; sortFullTree(); } }); ToolStrip toolStrip = new ToolStrip(); toolStrip.addSpacer(1); toolStrip.addButton(byPackage); toolStrip.addButton(byType); // Left -- Tree Grid TreeNode fullTreeRoot = new TreeNode(); fullTree.setRoot(fullTreeRoot); fullTree.setShowRoot(false); TreeNode resultsTreeRoot = new TreeNode(); resultsTree.setRoot(resultsTreeRoot); resultsTree.setShowRoot(false); treeGrid.setData(fullTree); treeGrid.setShowConnectors(true); treeGrid.setShowRollOver(false); treeGrid.addSelectionUpdatedHandler(selectedPipefilesHandler); treeGrid.addNodeContextClickHandler(contextClickHandler); // Left -- Selected Files numSelectedLabel.setHeight(25); numSelectedLabel.setAlign(Alignment.CENTER); numSelectedLabel.setStyleName("largerFont"); // Left final VLayout left = new VLayout(); left.setShowResizeBar(true); left.setCanDragResize(true); left.setResizeFrom("L", "R"); left.setWidth(300); left.setMinWidth(300); left.setMaxWidth(600); left.setAlign(Alignment.CENTER); left.setPadding(10); left.setBackgroundColor("#F5DEB3"); left.addMember(rootDirectoryDisplay); left.addMember(searchForm); left.addMember(toolStrip); left.addMember(treeGrid); left.addMember(numSelectedLabel); left.addResizedHandler(new ResizedHandler() { public void onResized (ResizedEvent event){ query.setWidth(left.getWidth() - 20); rootNew.setWidth(left.getWidth() - 20); } }); rootDirectoryDisplay.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event){ rootNew.setValue(rootDirectory.absolutePath); left.removeMember(rootDirectoryDisplay); left.addMember(rootForm, 0); rootForm.focusInItem(rootNew); } }); rootNew.addKeyUpHandler(new KeyUpHandler() { public void onKeyUp(KeyUpEvent event) { String pressed = event.getKeyName(); if (pressed.equals(KeyNames.ENTER)){ // Determine if the tree needs to be updated, set the rot directory String newRoot = rootNew.getValueAsString(); String oldRoot = rootDirectory.absolutePath; boolean updated = ( ! oldRoot.equals(newRoot) ); // Update the view rootDirectoryDisplay.setContents(newRoot); left.removeMember(rootForm); left.addMember(rootDirectoryDisplay, 0); // Get the directory if (updated){ getDirectory(newRoot); basicInstructions(); } } } }); // Main HLayout main = new HLayout(); main.setWidth100(); main.addMember(left); main.addMember(workarea); VLayout layout = new VLayout(); layout.setHeight100(); layout.setWidth100(); layout.addMember(header); layout.addMember(main); layout.draw(); // Tree Initialization getDirectory(rootDirectoryDefault); } //////////////////////////////////////////////////////////// // Private Function - Calls to Server //////////////////////////////////////////////////////////// /** * Makes the RPC to getDirectory */ private void getDirectory(final String absolutePath){ fileServer.getDirectory(absolutePath, new AsyncCallback<Directory>() { public void onFailure(Throwable caught) { error("Failed to retrieve directory: " + caught.getMessage()); } public void onSuccess(Directory result) { if (result != null){ // Set and display the rootDirectory rootDirectory = result; rootDirectoryDisplay.setContents(rootDirectory.absolutePath); // Update the files and groups updateFullTree(null); getGroups(false); } else { // Ask for new root directory Dialog dialog = new Dialog(); dialog.setWidth(300); dialog.setShowCloseButton(false); dialog.setShowModalMask(true); dialog.setButtons(Dialog.OK); SC.askforValue( "Invalid Root Directory", "Root directory does not exist or is not a directory", absolutePath, new ValueCallback(){ public void execute(String value) { getDirectory(value); } }, dialog ); } } }); } /** * Makes the RPC to getFiles */ private void getFiles(final int[] filesToSelect){ pipes.clear(); fileServer.getFiles(rootDirectory, new AsyncCallback<Pipefile[]>() { public void onFailure(Throwable caught) { error("Failed to retrieve files: " + caught.getMessage()); } public void onSuccess(Pipefile[] result) { if (result != null) { // Set pipes and packages LinkedHashSet<String> packageNames = new LinkedHashSet<String>(); for (Pipefile p : result){ pipes.put(p.fileId, p); packageNames.add(p.packageName); } packages = new String[packageNames.size()]; packages = packageNames.toArray(packages); // Update lastPipefile if ( !pipes.containsKey(lastPipefileId) ){ backToLastPipefile.hide(); } // Update the tree sortFullTree(); selectFiles(filesToSelect); } else { SC.say(rootDirectory.absolutePath + " contains no pipefiles"); } } } ); } /** * Makes the RPC to getSearchResults */ private void getSearchResults(String query){ fileServer.getSearchResults(rootDirectory, query, new AsyncCallback<Pipefile[]>() { public void onFailure(Throwable caught) { error("Failed to retrieve search results: "+ caught.getMessage()); } public void onSuccess(Pipefile[] result) { // Clear the ResultsTree resultsTree.removeList(resultsTree.getDescendants()); if (result != null){ for (Pipefile p : result){ if (pipes.containsKey(p.fileId) == false){ pipes.put(p.fileId, p); } TreeNode pipe = new TreeNode(p.name); pipe.setAttribute("fileId", p.fileId); pipe.setAttribute("viewable", true); resultsTree.add(pipe, resultsTree.getRoot()); } } } }); } /** * Makes the RPC to updateFile */ private void updateFile(final Pipefile pipe){ fileServer.updateFile(rootDirectory, pipe, new AsyncCallback<Void>() { public void onFailure(Throwable caught) { error("Failed to update file: " + caught.getMessage()); } public void onSuccess(Void result){ success("Successfully updated " + pipe.name); updateFullTree( new int[] { pipe.fileId } ); getGroups(false); basicInstructions(); } }); } /** * Makes the RPC to removeFiles, after confirmation */ private void removeFiles(final Pipefile[] selected){ SC.confirm( "Confirm Remove", "Please confirm that you want to remove the " + selected.length + " selected file(s)", new BooleanCallback(){ public void execute(Boolean value) { if (value){ fileServer.removeFiles(rootDirectory, selected, new AsyncCallback<Void>() { public void onFailure(Throwable caught) { error("Failed to remove file(s): " + caught.getMessage()); } public void onSuccess(Void result){ success("Successfully removed " + selected.length + " file(s)."); updateFullTree(null); basicInstructions(); } }); } } } ); } /** * Makes the RPC to copyFiles */ private void copyFiles(final Pipefile[] selected, final String packageName){ fileServer.copyFiles(rootDirectory, selected, packageName, new AsyncCallback<int[]>() { public void onFailure(Throwable caught) { error("Failed to copy file(s): " + caught.getMessage()); } public void onSuccess(int[] result){ success("Successfully copied " + selected.length + " file(s) to " + packageName + "."); updateFullTree(result); basicInstructions(); } }); } /** * Makes the RPC to moveFiles, after confirmation */ private void moveFiles(final Pipefile[] selected, final String packageName){ SC.confirm( "Confirm Move", "Please confirm that you want to move the " + selected.length + " selected file(s) to " + packageName, new BooleanCallback(){ public void execute(Boolean value) { if (value){ fileServer.moveFiles(rootDirectory, selected, packageName, new AsyncCallback<int[]>() { public void onFailure(Throwable caught) { error("Failed to move file(s): " + caught.getMessage()); } public void onSuccess(int[] result){ success("Successfully moved " + selected.length + " file(s) to " + packageName + "."); updateFullTree(result); basicInstructions(); } }); } } } ); } /** * Makes the RPC to getGroups */ private void getGroups(final boolean view){ groups.clear(); fileServer.getGroups(rootDirectory, new AsyncCallback<Group[]>() { public void onFailure(Throwable caught) { error("Failed to retrieve groups: " + caught.getMessage()); } public void onSuccess(Group[] result) { if (result != null){ for(Group g : result){ groups.put(g.name, g); } } if (view){ viewGroups(); } } }); } /** * Makes the RPC to updateGroup */ private void updateGroup(final Group group){ fileServer.updateGroup(rootDirectory, group, new AsyncCallback<Void>() { public void onFailure(Throwable caught) { error("Failed to update group: " + caught.getMessage()); } public void onSuccess(Void result) { getGroups(true); updateFullTree(null); success("Successfully updated " + group.name + "."); } }); } /** * Makes the RPC to removeGroups */ private void removeGroups(final Group[] groups){ SC.confirm( "Confirm Remove", "Please confirm that you want to remove the " + groups.length + " selected groups(s). <br/>" + "All references to this group will be removed", new BooleanCallback(){ public void execute(Boolean value) { if (value){ fileServer.removeGroups(rootDirectory, groups, new AsyncCallback<Void>(){ public void onFailure(Throwable caught) { error("Failed to remove groups: "+ caught.getMessage()); } public void onSuccess(Void result) { getGroups(true); updateFullTree(null); success("Successfully removed " + groups.length + " groups(s)."); } }); } } } ); } /** * Makes the HTTP request to download */ private void downloadFiles(Pipefile[] selected){ int length = selected.length; String url = "serverlibrarymanager/download?n=" + length; for(int i = 0; i < length; i++){ String filename = selected[i].absolutePath; url += "&filename_" + i + "=" + URL.encode(filename); } Window.open(url, "downloadWindow", ""); } //////////////////////////////////////////////////////////// // Private Functions - Tree //////////////////////////////////////////////////////////// private void selectFiles(int[] filesToSelect){ if (filesToSelect == null){ return; } Record[] records = new Record[filesToSelect.length]; int index = 0; for (int fileId : filesToSelect){ Pipefile pipe = pipes.get(fileId); String key = pipe.packageName + " > " + pipe.type + " > " + pipe.name; TreeNode node = nodes.get(key); TreeNode typeFolder = fullTree.getParent(node); TreeNode packageFolder = fullTree.getParent(typeFolder); fullTree.openFolder(packageFolder); fullTree.openFolder(typeFolder); records[index] = node; index++; } treeGrid.selectRecords(records); } private void sortFullTree(){ // Clear the map nodes.clear(); // Clear the full tree fullTree.removeList(fullTree.getDescendants()); for (Pipefile p : pipes.values()){ String primaryName, secondaryName; if (viewByPackage) { primaryName = p.packageName; secondaryName = p.type; } else { primaryName = p.type; secondaryName = p.packageName; } String primaryKey = primaryName; String secondaryKey = primaryName + " > " + secondaryName; // Primary Node TreeNode primaryNode; if (nodes.containsKey(primaryKey)){ primaryNode = nodes.get(primaryKey); } else { primaryNode = new TreeNode(primaryName); primaryNode.setAttribute("fileId", -1); primaryNode.setAttribute("key", primaryKey); primaryNode.setAttribute("viewable", false); primaryNode.setAttribute("moveHere", viewByPackage); fullTree.add(primaryNode, fullTree.getRoot()); nodes.put(primaryKey, primaryNode); } // Secondary Node TreeNode secondaryNode; if (nodes.containsKey(secondaryKey)){ secondaryNode = nodes.get(secondaryKey); } else { secondaryNode = new TreeNode(secondaryName); secondaryNode.setAttribute("fileId", -1); secondaryNode.setAttribute("key", secondaryKey); secondaryNode.setAttribute("viewable", false); secondaryNode.setAttribute("moveHere", !viewByPackage); fullTree.add(secondaryNode, primaryNode); nodes.put(secondaryKey, secondaryNode); } // Pipefile node String pipeKey = secondaryKey + " > " + p.name; TreeNode pipeNode = new TreeNode(p.name); pipeNode.setAttribute("fileId", p.fileId); pipeNode.setAttribute("key", secondaryKey + " > " + p.name); pipeNode.setAttribute("viewable", true); fullTree.add(pipeNode, secondaryNode); nodes.put(pipeKey, pipeNode); } } /** * Updates Package Tree and Module Tree based on the rootDirectory * Ensure tree is displayed */ private void updateFullTree(int[] filesToSelect){ // Clear the selection treeGrid.deselectAllRecords(); updateSelected(); fullTree.removeList(fullTree.getDescendants()); treeGrid.setData(fullTree); getFiles(filesToSelect); } /** * Updates ResultsTree based on the query * Ensure results are displayed */ private void updateResultsTree(final String query){ // Clear the selection treeGrid.deselectAllRecords(); updateSelected(); treeGrid.setData(resultsTree); getSearchResults(query); } //////////////////////////////////////////////////////////// // Private Functions - Workarea - File Operations //////////////////////////////////////////////////////////// /** * Adds file operations (download, remove, copy, move) to the workarea */ private void fileOperationsActions(final Pipefile[] pipefiles){ // Title Label workareaTitle = new Label("File Operations"); workareaTitle.setHeight(20); workareaTitle.setStyleName("workarea-title"); workarea.addMember(workareaTitle); // Actions final ComboBoxItem combo = new ComboBoxItem(); combo.setTitle("To Package"); combo.setValueMap(packages); DynamicForm form = new DynamicForm(); form.setItems(combo); Button remove = new Button("Remove"); Button download = new Button("Download"); Button copy = new Button("Copy"); Button move = new Button("Move"); remove.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event){ removeFiles(pipefiles); } }); download.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event){ downloadFiles(pipefiles); } }); copy.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event){ String value = combo.getValueAsString(); if (value == null || value.equals("")){ SC.say("Please specify a package"); } else { copyFiles(pipefiles, value); } } }); move.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event){ String value = combo.getValueAsString(); if (value == null || value.equals("")){ SC.say("Please specify a package"); } else { moveFiles(pipefiles, value); } } }); HLayout copyMoveButtons = new HLayout(10); copyMoveButtons.setAlign(Alignment.CENTER); copyMoveButtons.addMember(copy); copyMoveButtons.addMember(move); VLayout copyMoveLayout = new VLayout(5); copyMoveLayout.setPadding(5); copyMoveLayout.setWidth(250); copyMoveLayout.setHeight(80); copyMoveLayout.setShowEdges(true); copyMoveLayout.setDefaultLayoutAlign(Alignment.CENTER); copyMoveLayout.addMember(copyMoveButtons); copyMoveLayout.addMember(form); VLayout downloadLayout = new VLayout(); downloadLayout.setPadding(5); downloadLayout.setWidth(110); downloadLayout.setHeight(30); downloadLayout.setShowEdges(true); downloadLayout.addMember(download); VLayout removeLayout = new VLayout(); removeLayout.setPadding(5); removeLayout.setWidth(110); removeLayout.setHeight(30); removeLayout.setShowEdges(true); removeLayout.addMember(remove); final HLayout actions = new HLayout(10); actions.setHeight(100); actions.addMember(downloadLayout); actions.addMember(removeLayout); actions.addMember(copyMoveLayout); workarea.addMember(actions); } /** * Adds a list of the selected files to the workarea */ private void fileOperationsSelectedFiles(final Pipefile[] pipefiles){ // Title Label selectedTitle = new Label("Selected Files (" + pipefiles.length + ")"); selectedTitle.setHeight(20); selectedTitle.setStyleName("workarea-title"); workarea.addMember(selectedTitle); // Selected Files ListGrid grid = new ListGrid(); grid.setWidth(600); ListGridField nField = new ListGridField("name", "Name"); ListGridField pField = new ListGridField("packageName", "Package"); ListGridField tField = new ListGridField("type", "Type"); grid.setFields(nField, pField, tField); ListGridRecord[] records = new ListGridRecord[pipefiles.length]; for(int i = 0; i < pipefiles.length; i++){ Pipefile pipe = pipefiles[i]; ListGridRecord record = new ListGridRecord(); record.setAttribute("name", pipe.name); record.setAttribute("packageName", pipe.packageName); record.setAttribute("type", pipe.type); record.setAttribute("fileId", pipe.fileId); records[i] = record; } grid.setData(records); grid.addRecordClickHandler(new RecordClickHandler(){ public void onRecordClick(RecordClickEvent event) { Record clicked = event.getRecord(); int fileId = clicked.getAttributeAsInt("fileId"); Pipefile pipe = pipes.get(fileId); selected = new Pipefile[] { pipe }; //when single file is selected from the workarea's list, //remaining items will get deselected treeGrid.deselectAllRecords(); viewFile(pipe); } }); workarea.addMember(grid); } /** * Sets workarea to file Operations (download, remove, copy, move) * and a list of the selected files */ private void fileOperations(final Pipefile[] pipefiles){ clearWorkarea(); fileOperationsActions(pipefiles); fileOperationsSelectedFiles(pipefiles); } //////////////////////////////////////////////////////////// // Private Functions - Workarea - View File //////////////////////////////////////////////////////////// private String loopFound = "<b>LOOP IN GROUP DEPENDENCIES</b>"; private String groupHint = "Comma separated list<br/>" + "Group syntax = " + GroupSyntax.start + "groupName" + GroupSyntax.end + "<br/>Groups expanded below"; private String expandGroupsRecursive(String originalGroup, String list, String base){ String ret = ""; String[] agents = list.split(","); for(String agent : agents){ // Trim whitespace agent = agent.trim(); if (GroupSyntax.isGroup(agent)){ String group = GroupSyntax.agentToGroupname(agent); if (group.equals(originalGroup)){ ret += base + loopFound + "<br/>"; return ret; } else if (groups.containsKey(group)){ Group g = groups.get(group); ret += base + group + " = " + g.users + "<br/>"; ret += expandGroupsRecursive(originalGroup, g.users, base + "    "); } else { ret += base + group + " is undefined" + "<br/>";; } } } return ret; } /** * Updates a static text item with the groups expanded */ private boolean expandGroups(String groupName, String agentList, StaticTextItem info){ String msg = expandGroupsRecursive(groupName, agentList, ""); info.setValue(msg); return msg.contains(loopFound); } /** * Sets the workarea with file operations and a form to edit */ private void viewFile(final Pipefile pipe){ clearWorkarea(); lastPipefileId = pipe.fileId; backToLastPipefile.hide(); // File Operations fileOperationsActions(new Pipefile[] {pipe}); // Title Label editFileTitle = new Label("Edit File"); editFileTitle.setHeight(40); editFileTitle.setStyleName("workarea-title"); workarea.addMember(editFileTitle); // Edit File final DynamicForm form = new DynamicForm(); form.setCanEdit(true); form.setPadding(10); form.setStyleName("edit-form"); int width = 400; TextItem name = new TextItem(); name.setTitle("Name"); name.setName("name"); name.setWidth(width); TextItem packageName = new TextItem(); packageName.setTitle("Package"); packageName.setName("package"); packageName.setWidth(width); StaticTextItem type = new StaticTextItem(); type.setTitle("Type"); type.setName("type"); TextAreaItem description = new TextAreaItem(); description.setTitle("Description"); description.setName("description"); description.setWidth(width); TextItem tags = new TextItem(); tags.setTitle("Tags"); tags.setName("tags"); tags.setWidth(width); tags.setHint("Comma separated list"); SelectItem formatType = new SelectItem(); formatType.setTitle("Value Format Type"); formatType.setType("comboBox"); formatType.setName("formatType"); final String str="String", dir="Directory", file="File", num="Number"; formatType.setValueMap(str, dir, file, num); TextAreaItem values = new TextAreaItem(); values.setTitle("Values"); values.setName("values"); values.setWidth(width); values.setHint("Newline separated list<br/>"); final TextItem valuesPrefix = new TextItem(); valuesPrefix.setTitle("Values Prefix"); valuesPrefix.setName("valuesPrefix"); valuesPrefix.setWidth(width); TextItem location = new TextItem(); location.setTitle("Location"); location.setName("location"); location.setWidth(width); TextItem locationPrefix = new TextItem(); locationPrefix.setTitle("Location Prefix"); locationPrefix.setName("locationPrefix"); locationPrefix.setWidth(width); TextItem uri = new TextItem(); uri.setTitle("URI"); uri.setName("uri"); uri.setWidth(width); final TextAreaItem access = new TextAreaItem(); access.setTitle("Access"); access.setName("access"); access.setWidth(width); access.setHeight(50); access.setHint(groupHint); final StaticTextItem accessInfo = new StaticTextItem(); accessInfo.setTitle("Access Groups Expanded"); formatType.addChangedHandler(new ChangedHandler(){ public void onChanged(ChangedEvent event){ if(form.getValueAsString("formatType").equals(num)){ valuesPrefix.disable(); } else valuesPrefix.enable(); } }); access.addChangedHandler(new ChangedHandler(){ public void onChanged(ChangedEvent event){ expandGroups("", access.getValueAsString(), accessInfo); } }); form.setFields(name, packageName, type, description, tags, locationPrefix, location, uri, valuesPrefix, values, formatType, access, accessInfo); // Set the value of the fields form.setValue("name", pipe.name); form.setValue("package", pipe.packageName); if(pipe.type.equals("Modules")) form.setValue("type", "Module"); else if(pipe.type.equals("Groups")) form.setValue("type", "Group"); else form.setValue("type", pipe.type); form.setValue("description", pipe.description); form.setValue("tags",pipe.tags); form.setValue("access", pipe.access); expandGroups("", access.getValueAsString(), accessInfo); if(pipe.type.equals("Data")){ String valString = ""; pipe.valuesPrefix = ""; RegExp split = RegExp.compile("\n", "m"); SplitResult vals = split.split(pipe.values); RegExp re = RegExp.compile("((.*/)*)(.*)"); for (int j = 0; j<vals.length(); j++){ MatchResult m = re.exec(vals.get(j)); if(m != null && m.getGroup(0) !=null && m.getGroup(0).length()>0){ //check if group is null before assigning if(m.getGroup(3) != null) valString += m.getGroup(3) + "\n"; if(j==0){ if(m.getGroup(2) != null) pipe.valuesPrefix = m.getGroup(2); }else{ if(m.getGroup(2) == null || !pipe.valuesPrefix.equals(m.getGroup(2))){ pipe.valuesPrefix = ""; } } } if(pipe.valuesPrefix.equals("")) valString = pipe.values; } form.setValue("formatType", pipe.formatType); if(pipe.formatType.equals(file) || pipe.formatType.equals(dir) || pipe.formatType.equals(str)) form.setValue("valuesPrefix", pipe.valuesPrefix); else valuesPrefix.disable(); form.setValue("values", valString); } else{ form.hideItem("values"); form.hideItem("valuesPrefix"); form.hideItem("formatType"); } if(pipe.type.equals("Modules")){ String loc = ""; pipe.locationPrefix = ""; RegExp re = RegExp.compile("(.*://.*/)(.*)"); MatchResult m = re.exec(pipe.location); if(m != null){ pipe.locationPrefix = m.getGroup(1); loc = m.getGroup(2); } else{ pipe.locationPrefix = ""; loc = ""; } form.setValue("locationPrefix", pipe.locationPrefix); form.setValue("location", loc); } else { form.hideItem("locationPrefix"); form.hideItem("location"); } if(pipe.type.equals("Modules") || pipe.type.equals("Groups")){ form.setValue("uri", pipe.uri); } else { form.hideItem("uri"); } // Update Button Button update = new Button("Update"); update.addClickHandler( new ClickHandler() { public void onClick(ClickEvent event) { String newName = form.getValueAsString("name"); pipe.nameUpdated = ( ! pipe.name.equals(newName) ); String newPackageName = form.getValueAsString("package"); pipe.packageUpdated = ( ! pipe.packageName.equals(newPackageName)); pipe.name = newName; pipe.packageName = newPackageName; // pipe.type is not editable pipe.description = form.getValueAsString("description"); pipe.tags = form.getValueAsString("tags"); pipe.access = form.getValueAsString("access"); if(pipe.type.equals("Data")){ String valString = ""; if(form.getValueAsString("formatType").equals(num)){ valString = form.getValueAsString("values"); } else{ //append prefix pipe.valuesPrefix = form.getValueAsString("valuesPrefix"); if(pipe.valuesPrefix == null) pipe.valuesPrefix = ""; RegExp split = RegExp.compile("\n", "m"); SplitResult vals = split.split(form.getValueAsString("values")); for (int j = 0; j<vals.length(); j++){ if(vals.get(j).length()==0) continue; valString += pipe.valuesPrefix + vals.get(j) + "\n"; } } pipe.values = valString; pipe.formatType = form.getValueAsString("formatType"); } if (pipe.type.equals("Modules")){ pipe.locationPrefix = form.getValueAsString("locationPrefix"); pipe.location = pipe.locationPrefix + form.getValueAsString("location"); } if (pipe.type.equals("Modules") || pipe.type.equals("Groups")){ pipe.uri = form.getValueAsString("uri"); } updateFile(pipe); } }); Button cancel = new Button("Cancel"); cancel.addClickHandler(new ClickHandler(){ public void onClick(ClickEvent event){ basicInstructions(); } }); HLayout buttonRow = new HLayout(10); buttonRow.addMember(update); buttonRow.addMember(cancel); workarea.addMember(form); workarea.addMember(buttonRow); } //////////////////////////////////////////////////////////// // Private Functions - Workarea - Groups //////////////////////////////////////////////////////////// /** * Sets workarea to a list of the groups */ private void viewGroups(){ clearWorkarea(); int width = 600; // Title Label title = new Label("Manage Groups"); title.setHeight(30); title.setStyleName("workarea-title"); // Description Label description = new Label( "Double click a group to edit it " + "or mark the checkboxes of groups you want to delete then click \"Remove Selected Groups\"<br/>" + "Groups without a checkbox are in use and cannot be deleted. More info can be found in the edit screen." ); description.setHeight(50); description.setStyleName("workarea-description"); // Group Grid ListGridField nField = new ListGridField("name", "Name"); ListGridField uField = new ListGridField("users", "Users"); final ListGrid grid = new ListGrid(); grid.setFields(nField, uField); grid.setWidth(width); grid.setSelectionAppearance(SelectionAppearance.CHECKBOX); Collection<Group> groupsCollection = groups.values(); ListGridRecord[] records = new ListGridRecord[groupsCollection.size()]; int i = 0; for(Group group : groupsCollection){ ListGridRecord record = new ListGridRecord(); record.setAttribute("name", group.name); record.setAttribute("users", group.users); records[i++] = record; } grid.setData(records); grid.addRecordDoubleClickHandler(new RecordDoubleClickHandler(){ public void onRecordDoubleClick(RecordDoubleClickEvent event){ Record r = event.getRecord(); String groupName = r.getAttribute("name"); Group g = groups.get(groupName); editGroup(g); } }); // ToolStrip Label total = new Label(records.length + " groups"); ToolStripButton newGroup = new ToolStripButton(); newGroup.setIcon("[SKIN]/actions/add.png"); newGroup.setPrompt("Add New Group"); newGroup.addClickHandler(new ClickHandler(){ public void onClick(ClickEvent event){ Group newGroup = new Group(); editGroup(newGroup); } }); ToolStripButton removeGroups = new ToolStripButton(); removeGroups.setIcon("[SKIN]/actions/remove.png"); removeGroups.setPrompt("Remove Selected Groups"); removeGroups.addClickHandler(new ClickHandler(){ public void onClick(ClickEvent event){ ListGridRecord[] selected = grid.getSelectedRecords(); if (selected != null && selected.length > 0){ final Group[] toRemove = new Group[selected.length]; int i = 0; for(ListGridRecord r : selected){ String name = r.getAttribute("name"); toRemove[i++] = groups.get(name); } removeGroups(toRemove); } } }); ToolStrip bottom = new ToolStrip(); bottom.setWidth100(); bottom.addMember(total); bottom.addFill(); bottom.addButton(newGroup); bottom.addButton(removeGroups); grid.setGridComponents(new Object[] { ListGridComponent.HEADER, ListGridComponent.BODY, bottom }); workarea.addMember(title); workarea.addMember(description); workarea.addMember(grid); } /** * Sets workarea to a form to edit a group */ private void editGroup(final Group g){ clearWorkarea(); final boolean newGroup = (g.groupId == -1); int width = 400; // Title Label title = new Label(newGroup ? "New Group" : "Edit Group"); title.setHeight(30); title.setStyleName("workarea-title"); // Form for editing final TextItem name = new TextItem("Name"); name.setValue(g.name); name.setWidth(width); final TextAreaItem agents = new TextAreaItem("Agents"); agents.setValue(g.users); agents.setWidth(width); agents.setHeight(50); agents.setHint(groupHint); final StaticTextItem agentsInfo = new StaticTextItem(); agentsInfo.setTitle("Agent Groups Expanded"); agents.addChangedHandler(new ChangedHandler(){ public void onChanged(ChangedEvent event){ expandGroups(name.getValueAsString(), agents.getValueAsString(), agentsInfo); } }); DynamicForm form = new DynamicForm(); form.setFields(name, agents, agentsInfo); form.setPadding(10); expandGroups(name.getValueAsString(), agents.getValueAsString(), agentsInfo); Button update = new Button("Update"); update.addClickHandler(new ClickHandler(){ public void onClick(ClickEvent event){ String nameValue = name.getValueAsString(); String usersValue = agents.getValueAsString(); boolean loop = expandGroups(g.name, usersValue, agentsInfo); if (nameValue == null || nameValue.equals("")){ SC.say("Name cannot be blank"); } else if (newGroup && groups.containsKey(nameValue)){ SC.say("Name (" + g.name + ") is already in use. Please choose another name."); } else if (loop){ SC.say("Loop in group dependencies. Please remove this loop."); } else { g.name = nameValue; g.users = usersValue; updateGroup(g); } } }); Button cancel = new Button("Cancel"); cancel.addClickHandler(new ClickHandler(){ public void onClick(ClickEvent event){ viewGroups(); } }); HLayout buttonRow = new HLayout(10); buttonRow.addMember(update); buttonRow.addMember(cancel); workarea.addMember(title); workarea.addMember(form); workarea.addMember(buttonRow); } //////////////////////////////////////////////////////////// // Private Functions - Workarea - Import //////////////////////////////////////////////////////////// /** * Sets workarea to an import form */ private void importForm(){ clearWorkarea(); // Title Label title = new Label("Import File(s)"); title.setHeight(30); title.setStyleName("workarea-title"); // Uses GWT form components so we can submit in the background Grid grid = new Grid(4,3); final FormPanel uploadForm = new FormPanel(); uploadForm.setWidget(grid); uploadForm.setEncoding(FormPanel.ENCODING_MULTIPART); uploadForm.setMethod(FormPanel.METHOD_POST); uploadForm.setAction(GWT.getModuleBaseURL()+"upload"); // Package Name Label packageLabel = new Label("Package"); packageLabel.setHeight(30); final TextBox packageName = new TextBox(); packageName.setName("packageName"); packageName.setWidth("300px"); Label packageDescription = new Label ( "Set package to put all uploaded files into that package.<br/>" + "If empty all files will be placed in the package specified in the file" ); packageDescription.setHeight(30); packageDescription.setWidth(500); packageDescription.setStyleName("workarea-description"); grid.setWidget(0, 0, packageLabel); grid.setWidget(0, 1, packageName); grid.setWidget(0, 2, packageDescription); // Upload local file Label uploadLabel = new Label("Upload Local Files"); uploadLabel.setHeight(40); FileUpload fileItem = new FileUpload(); fileItem.setName("theMostUniqueName"); Scheduler.get().scheduleDeferred(new Command(){ @Override public void execute(){ enableUpload(); //FROM :: http://forums.smartclient.com/showthread.php?t=16007 } }); Label uploadDescription = new Label ( "Select local files to upload. Accepts \".pipe\" files only. All other files are discarded." ); uploadDescription.setHeight(30); uploadDescription.setWidth(500); uploadDescription.setStyleName("workarea-description"); grid.setWidget(1, 0, uploadLabel); grid.setWidget(1, 1, fileItem); grid.setWidget(1, 2, uploadDescription); // Upload URLs Label urlLabel = new Label("Upload From URLs"); urlLabel.setHeight(40); final TextArea urls = new TextArea(); urls.setName("urls"); urls.setWidth("300px"); urls.setHeight("100px"); Label urlDescription = new Label ( "Enter a newline seperated list of urls." ); urlDescription.setHeight(40); urlDescription.setWidth(400); urlDescription.setStyleName("workarea-description"); grid.setWidget(2, 0, urlLabel); grid.setWidget(2, 1, urls); grid.setWidget(2, 2, urlDescription); Button uploadButton = new Button("Send"); uploadButton.addClickHandler(new ClickHandler(){ public void onClick(ClickEvent event) { uploadForm.submit(); } }); grid.setWidget(3, 0, uploadButton); uploadForm.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() { public void onSubmitComplete(SubmitCompleteEvent event) { if( event.getResults().length() == 0) { success("Successfully uploaded files"); } else { error("Failed to upload files: " + event.getResults()); } updateFullTree(null); basicInstructions(); } }); // Root Directory Hidden hRoot = new Hidden(); hRoot.setName("root"); hRoot.setValue(rootDirectory.absolutePath); grid.setWidget(3, 1, hRoot); workarea.addMember(title); workarea.addMember(uploadForm); } // FROM :: http://forums.smartclient.com/showthread.php?t=16007 // Allows making multiple selection of files private native void enableUpload() /*-{ var newAttr= document.createAttribute('multiple'); newAttr.nodeValue='multiple'; $wnd.document.getElementsByName('theMostUniqueName')[0].setAttributeNode(newAttr); }-*/; //////////////////////////////////////////////////////////// // Private Functions - Workarea - Home //////////////////////////////////////////////////////////// /** * Sets workarea to the basic instructions */ private void basicInstructions(){ clearWorkarea(); Label root = new Label("This is your root directory. Click on it to edit."); root.setIcon("leftarrow.jpg"); root.setIconWidth(30); root.setHeight(40); root.setStyleName("workarea-description"); root.setValign(VerticalAlignment.TOP); Label search = new Label("Use this to search for files. Search must be at least 2 letters."); search.setIcon("leftarrow.jpg"); search.setIconWidth(30); search.setHeight(30); search.setStyleName("workarea-description"); search.setValign(VerticalAlignment.TOP); Label view = new Label("Use these buttons to reorder the hierarchy"); view.setIcon("leftarrow.jpg"); view.setIconWidth(30); view.setHeight(50); view.setStyleName("workarea-description"); view.setValign(VerticalAlignment.TOP); workarea.addMember(root); workarea.addMember(search); workarea.addMember(view); Label files = new Label( "Select any file to view and edit its properties and perform file operations<br/>" + "You can also select multiple files at once and perform the same operation on all of them" ); files.setHeight(60); files.setStyleName("workarea-description"); files.setValign(VerticalAlignment.TOP); workarea.addMember(files); } //////////////////////////////////////////////////////////// // Private Functions - Workarea - Messages //////////////////////////////////////////////////////////// /** * Prints an error message to the top of workarea */ private void error(String message){ SC.say(message); } /** * Prints a success message to the top of workarea */ private void success(String msg){ message.setContents(msg); message.animateShow(AnimationEffect.FADE); // Clear the message after 5 seconds new Timer() { public void run() { message.animateHide(AnimationEffect.FADE); } }.schedule(5000); } //////////////////////////////////////////////////////////// // Private Functions - Workarea - Clear //////////////////////////////////////////////////////////// /** * Clears the workarea */ private void clearWorkarea(){ if (pipes.containsKey(lastPipefileId)){ Pipefile pipe = pipes.get(lastPipefileId); backToLastPipefile.setTitle("Back to " + pipe.name); backToLastPipefile.show(); } workarea.removeMembers(workarea.getMembers()); } }